﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Scriptor.Presentation.Entity;
using System.IO;
using Scriptor.Presentation.Templates;
using Scriptor.Presentation.Core;
using System.Windows.Forms;
using Scriptor.Presentation.Enumerator;

namespace Scriptor.Presentation.Core
{
    public class Generate
    {
        public static void GenerateDCFiles(List<Entidade> list, DirectoryInfo dir, int DCType, string pModulo, string pSubModulo)
        {
            string DC = string.Empty;
            if (DCType == 0)
            {
                DC = "Request";
            }
            else if (DCType == 1)
            {
                DC = "Response";
            }

            foreach (Entidade ent in list)
            {
                TextWriter twDC = new StreamWriter(dir.FullName + "\\" + DC + "\\" + ent.NomeEntidade + DC + ".cs", true, Encoding.UTF8);
                DCTemplate dc = new DCTemplate();

                string pUsing = string.Empty;
                if(Core.config.showUsing)
                    pUsing = dc.strUsing();

                string pDCNameSpace = string.Format("Sinacor.Servico.{0}.{1}.Service.DataContract." + DC, pModulo, pSubModulo);

                string pDCClassScope = dc.strDContract(pDCNameSpace, ent.NomeEntidade + DC, Core.config.showDecorators);

                StringBuilder stb = new StringBuilder();

                foreach (Propriedades prp in ent.ListaPropriedades)
                {
                    stb.Append(dc.strPropertie(prp, ent, Core.config.showDecorators));
                }

                pDCClassScope = dc.AppendProperties(pDCClassScope, stb);

                twDC.WriteLine(pUsing);
                twDC.WriteLine(pDCClassScope);

                twDC.Close();
            }
        }

        public static void GenerateDCTranslatorFile(DirectoryInfo dir, string pClassName, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string folderDC = "DataContractToBusinessEntity";

            TextWriter twDC = new StreamWriter(dir.FullName + "\\" + folderDC + "\\" + pClassName + ".cs", true, Encoding.UTF8);

            TranslatorTemplate tt = new TranslatorTemplate();

            string pUsing = string.Empty;
            
            if(Core.config.showUsing)
                pUsing = tt.strUsing(Enumerator.Enums.OrigemEnum.DataContract);

            string pDCNameSpace = str.Substring(0, str.IndexOf("ServiceContract")) + "ServiceImplementation.Translator." + folderDC;
            
            string pDCClassScope = tt.strTranslator(pDCNameSpace, pClassName);

            StringBuilder stb = new StringBuilder();

            List<Entidade> listTemp = new List<Entidade>();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    foreach (Param param in mtd.ParamList)
                    {
                        Entidade entIn = null;

                        if (param.ParameterIsParameter)
                        {
                            entIn = new Entidade(param.ParameterType, Enums.Direction.Parameter);
                        }
                        else
                        {
                            entIn = new Entidade(param.ParameterType, Enums.Direction.Entrada);
                        }

                        var Entity = listTemp.Find(delegate(Entidade x)
                        {
                            return (x.NomeEntidade == entIn.NomeEntidade && x.Sentido == entIn.Sentido);
                        });

                        if (Entity == null)
                        {
                            stb.Append(tt.strMethod(mtd, 1, param));
                            listTemp.Add(entIn);
                        }
                    }
                }
            }

            pDCClassScope = tt.AppendMethod(pDCClassScope, stb);

            twDC.WriteLine(pUsing);
            twDC.WriteLine(pDCClassScope);

            twDC.Close();
        }

        public static void GenerateCommunicationTranslatorFile(DirectoryInfo dir, string pClassName, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string[] pCommunication = str.Split('.');

            string folderDC = dir.Parent.Parent.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Communication" + "\\" + "Translator" + "\\" + "DataContractToModel" + "\\" + pClassName + ".cs";
            string folderMD = dir.Parent.Parent.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Communication" + "\\" + "Translator" + "\\" + "ModelToDataContract" + "\\" + pClassName + ".cs";

            string nameSpaceDC = string.Format("Sinacor.UI.{0}.{1}.Communication.Translator.DataContractToModel",pCommunication[2],pCommunication[3]);
            string nameSpaceMD = string.Format("Sinacor.UI.{0}.{1}.Communication.Translator.ModelToDataContract", pCommunication[2], pCommunication[3]);

            OutPutFile(folderDC, nameSpaceDC, str, plistaExterna, pTrv, pClassName,2);
            OutPutFile(folderMD, nameSpaceMD, str, plistaExterna, pTrv, pClassName,3);
        }

        private static void OutPutFile(string path, string pNameSpace, string str, List<Method> plistaExterna, TreeView pTrv, string pClassName, int MethodType)
        {
            TextWriter twDC = new StreamWriter(path, true, Encoding.UTF8);

            TranslatorTemplate tt = new TranslatorTemplate();

            string pUsing = string.Empty;

            if(Core.config.showUsing)
                pUsing = tt.strUsing(Enumerator.Enums.OrigemEnum.Communication);

            string pDCClassScope = tt.strTranslator(pNameSpace, pClassName);

            StringBuilder stb = new StringBuilder();

            List<Entidade> listTemp = new List<Entidade>();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    foreach (Param param in mtd.ParamList)
                    {
                        Entidade entIn = null;

                        if (param.ParameterIsParameter)
                        {
                            entIn = new Entidade(param.ParameterType, Enums.Direction.Parameter);
                        }
                        else
                        {
                            entIn = new Entidade(param.ParameterType, Enums.Direction.Entrada);
                        }

                        var Entity = listTemp.Find(delegate(Entidade x)
                        {
                            return (x.NomeEntidade == entIn.NomeEntidade && x.Sentido == entIn.Sentido);
                        });

                        if (Entity == null)
                        {
                            stb.Append(tt.strMethod(mtd, MethodType, param));
                            listTemp.Add(entIn);
                        }
                    }
                }
            }

            pDCClassScope = tt.AppendMethod(pDCClassScope, stb);

            twDC.WriteLine(pUsing);
            twDC.WriteLine(pDCClassScope);

            twDC.Close();
        }

        public static void GenerateBETranslatorFile(DirectoryInfo dir, string pClassName, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string folderBE = "BusinessEntityToDataContract";

            TextWriter twBE = new StreamWriter(dir.FullName + "\\" + folderBE + "\\" + pClassName + ".cs", true, Encoding.UTF8);
            TranslatorTemplate tt = new TranslatorTemplate();

            string pUsing = string.Empty;
            
            if(Core.config.showUsing)
                pUsing = tt.strUsing(Enumerator.Enums.OrigemEnum.BusinessEntity);
            
            string pBENameSpace = str.Substring(0, str.IndexOf("ServiceContract")) + "ServiceImplementation.Translator." + folderBE;
            
            string pBEClassScope = tt.strTranslator(pBENameSpace, pClassName);

            StringBuilder stb = new StringBuilder();

            List<Entidade> listTemp = new List<Entidade>();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    if (!string.IsNullOrEmpty(mtd.ReturnName))
                    {
                        Entidade entOut = new Entidade(mtd.ReturnName, Enums.Direction.Saida);
                        var Entity = listTemp.Find(delegate(Entidade x)
                        {
                            return (x.NomeEntidade == entOut.NomeEntidade && x.Sentido == entOut.Sentido);
                        });

                        if (Entity == null)
                        {
                            stb.Append(tt.strMethod(mtd, 0, new Param()));
                            listTemp.Add(entOut);
                        }
                    }
                }
            }

            pBEClassScope = tt.AppendMethod(pBEClassScope, stb);

            twBE.WriteLine(pUsing);
            twBE.WriteLine(pBEClassScope);

            twBE.Close();

        }
        
        public static void GenerateImplementationFile(DirectoryInfo dir, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string[] pInterface = str.Split('.');

            TextWriter tw = new StreamWriter(dir.FullName + "\\" + "ServiceImplementation" + "\\" + pInterface[6].Substring(1) + ".cs", true, Encoding.UTF8);

            ServiceImplementationTemplate sv = new ServiceImplementationTemplate();
            string pUsing = string.Empty;
            
            if(Core.config.showUsing)
                pUsing = sv.strUsing();

            string pNameSpace = str.Substring(0, str.IndexOf("I") - 1);
            string pClassName = pInterface[6].Substring(1);
            string pClassScope = sv.strImplementation(pNameSpace, pClassName, Core.config.showDecorators, Core.config.showInheritingOnImplementation);

            StringBuilder stb = new StringBuilder();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    stb.Append(sv.strMethod(mtd));
                }
            }

            pClassScope = sv.AppendMethod(pClassScope, stb);

            tw.WriteLine(pUsing);
            tw.WriteLine(pClassScope);

            tw.Close();
        }

        public static void GenerateInterfaceFile(DirectoryInfo dir, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string[] pInterface = str.Split('.');

            TextWriter tw = new StreamWriter(dir.FullName + "\\" + "ServiceContract" + "\\" + pInterface[6] + ".cs", true, Encoding.UTF8);

            InterfaceTemplate it = new InterfaceTemplate();
            
            string pUsing = string.Empty;
            if(Core.config.showUsing)
                pUsing = it.strUsing();

            string pNameSapace = str.Substring(0, str.IndexOf("I") - 1);
            string pInterfaceName = pInterface[6];
            string pInterfaceScope = it.strInterface(pNameSapace, pInterfaceName,Core.config.showDecorators);

            StringBuilder stb = new StringBuilder();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    stb.Append(it.strMethod(mtd, Core.config.showDecorators));
                }
            }

            pInterfaceScope = it.AppendMethod(pInterfaceScope, stb);

            tw.WriteLine(pUsing);
            tw.WriteLine(pInterfaceScope);

            tw.Close();
        }

        public static void GenerateCommunicationFile(DirectoryInfo dir, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string[] pCommunication = str.Split('.');
            string pCommunicationName = pCommunication[6].Substring(1);

            TextWriter tw = new StreamWriter(dir.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Communication" + "\\" + pCommunicationName + ".cs", true, Encoding.UTF8);

            CommunicationTemplate ct = new CommunicationTemplate();
            
            string pUsing = string.Empty;
            if(Core.config.showUsing)
                pUsing = ct.strUsing();

            string pNameSapace = string.Format("Sinacor.UI.{0}.{1}.Communication", pCommunication[2], pCommunication[3]);
            string pCommunicationScope = ct.strCommunication(pNameSapace, pCommunicationName, Core.config.showInheriting);

            StringBuilder stb = new StringBuilder();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    stb.Append(ct.strMethod(mtd));
                }
            }

            pCommunicationScope = ct.AppendMethod(pCommunicationScope, stb);

            tw.WriteLine(pUsing);
            tw.WriteLine(pCommunicationScope);

            tw.Close();
        }

        public static void GenerateEnumFiles(List<Enumeradores> list, DirectoryInfo dir, string pModulo, string pSubModulo, Enums.OrigemEnum source)
        {
            if (list == null)
                return;

            foreach (Enumeradores en in list)
            {
                string path = string.Empty;

                if (source == Enums.OrigemEnum.DataContract)
                    path = dir.FullName;
                else
                    if (source == Enums.OrigemEnum.BusinessEntity)
                        path = dir.Parent.Parent.FullName + "\\" + "BusinessEntity";
                    else
                        if (source == Enums.OrigemEnum.Model)
                            path = dir.Parent.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Model";

                TextWriter tw = new StreamWriter(path + "\\" + "Enum" + "\\" + en.nomeEnum + ".cs", true, Encoding.UTF8);

                EnumTemplate enm = new EnumTemplate();
                string pUsing = string.Empty;
                
                if(Core.config.showUsing)
                    pUsing = enm.strUsing(source);

                string pNameSpace = string.Empty;

                if (source == Enums.OrigemEnum.DataContract)
                    pNameSpace = string.Format("Sinacor.Servico.{0}.{1}.Service.DataContract.Enum", pModulo, pSubModulo);
                else
                    if (source == Enums.OrigemEnum.BusinessEntity)
                        pNameSpace = string.Format("Sinacor.Servico.{0}.{1}.BusinessEntity.Enum", pModulo, pSubModulo);
                    else
                        if (source == Enums.OrigemEnum.Model)
                            pNameSpace = string.Format("Sinacor.UI.{0}.{1}.Model.Enum", pModulo, pSubModulo);

                string pEnumScope = enm.strEnum(pNameSpace, en.nomeEnum);

                StringBuilder stb = new StringBuilder();

                foreach (object obj in en.itemsEnum)
                {
                    stb.Append(enm.strEnumItem(obj.ToString(),source, Core.config.showDecorators));
                }

                pEnumScope = enm.AppendEnumItem(pEnumScope, stb);

                tw.WriteLine(pUsing);
                tw.WriteLine(pEnumScope);

                tw.Close();
            }
        }

        public static void GenerateBEFiles(List<Entidade> listBusinessEntity, DirectoryInfo dir, string pModulo, string pSubModulo, bool isParameter)
        {
            string sufixo = string.Empty;
            string sufixoNamespace = string.Empty;

            if (isParameter)
            {
                sufixo = "Parameter\\";
                sufixoNamespace = ".Parameter";
            }

            foreach (Entidade ent in listBusinessEntity)
            {
                TextWriter twBE = new StreamWriter(dir.Parent.Parent.FullName + "\\" + "BusinessEntity" + "\\" + sufixo + ent.NomeEntidade + ".cs", true, Encoding.UTF8);
                BusinessEntityTemplate be = new BusinessEntityTemplate();

                string pUsing = string.Empty;
                
                if(Core.config.showUsing)
                    pUsing = be.strUsing();

                string pBENameSpace = string.Format("Sinacor.Servico.{0}.{1}.BusinessEntity" + sufixoNamespace, pModulo, pSubModulo);

                string pBEClassScope = be.strBusinessEntity(pBENameSpace, ent.NomeEntidade, Core.config.showInheriting);

                StringBuilder stb = new StringBuilder();

                foreach (Propriedades prp in ent.ListaPropriedades)
                {
                    stb.Append(be.strPropertie(prp, ent));
                }

                pBEClassScope = be.AppendProperties(pBEClassScope, stb);

                twBE.WriteLine(pUsing);
                twBE.WriteLine(pBEClassScope);

                twBE.Close();
            }
        }

        public static void GenerateMethodAssignFiles(DirectoryInfo dir, string str, List<Method> plistaExterna, TreeView pTrv, Enums.OrigemEnum source)
        {
            string path = dir.Parent.FullName;
            string pClassName = str.Split('.')[6].Substring(1);
            string pNameSpace = string.Empty;

            switch (source)
            {
                case Enums.OrigemEnum.DataContract:
                    break;
                case Enums.OrigemEnum.BusinessEntity:
                    break;
                case Enums.OrigemEnum.BusinessLogic:
                    path += "\\" + "BusinessLogic";
                    pNameSpace = string.Format("Sinacor.Servico.{0}.{1}.BusinessLogic", str.Split('.')[2],str.Split('.')[3]);
                    break;
                case Enums.OrigemEnum.ResourceAccess:
                    path += "\\" + "ResourceAccess";
                    pNameSpace = string.Format("Sinacor.Servico.{0}.{1}.ResourceAccess", str.Split('.')[2], str.Split('.')[3]);
                    break;
                default:
                    break;
            }

            TextWriter tw = new StreamWriter(path + "\\" + pClassName + ".cs", true, Encoding.UTF8);

            MethodAssignFilesTemplate met = new MethodAssignFilesTemplate();

            string pUsing = string.Empty;
            
            if(Core.config.showUsing)
                pUsing = met.strUsing(source);

            string pClassScope = met.strScope(pNameSpace, pClassName, source, Core.config.showInheriting);

            StringBuilder stb = new StringBuilder();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    stb.Append(met.strMethod(mtd));
                }
            }

            pClassScope = met.AppendMethod(pClassScope, stb);

            tw.WriteLine(pUsing);
            tw.WriteLine(pClassScope);

            tw.Close();
        }

        public static void GenerateModelFiles(List<Entidade> listBusinessEntity, DirectoryInfo dir, string pModulo, string pSubModulo, bool isParameter)
        {
            string sufixo = string.Empty;
            string sufixoNamespace = string.Empty;

            if (isParameter)
            {
                sufixo = "Parameter\\";
                sufixoNamespace = ".Parameter";
            }

            foreach (Entidade ent in listBusinessEntity)
            {
                TextWriter twModel = new StreamWriter(dir.Parent.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Model" + "\\" + sufixo + ent.NomeEntidade + ".cs", true, Encoding.UTF8);
                ModelTemplate mt = new ModelTemplate();

                string pUsing = string.Empty;

                if(Core.config.showUsing)
                    pUsing = mt.strUsing();

                string pModelNameSpace = string.Format("Sinacor.UI.{0}.{1}.Model" + sufixoNamespace, pModulo, pSubModulo);

                string pModelClassScope = mt.strModel(pModelNameSpace, ent.NomeEntidade, Core.config.showDecorators, Core.config.showInheriting);

                StringBuilder stb = new StringBuilder();

                foreach (Propriedades prp in ent.ListaPropriedades)
                {
                    stb.Append(mt.strPropertie(prp, ent));
                }

                pModelClassScope = mt.AppendProperties(pModelClassScope, stb);

                twModel.WriteLine(pUsing);
                twModel.WriteLine(pModelClassScope);

                twModel.Close();
            }
        }

        public static void GeneratePresenterFile(DirectoryInfo dir, string str, List<Method> plistaExterna, TreeView pTrv)
        {
            string[] pPresenter = str.Split('.');
            string pPresenterName = pPresenter[6].Substring(1);

            TextWriter tw = new StreamWriter(dir.Parent.Parent.FullName + "\\" + "UI" + "\\" + "Presenter" + "\\" + pPresenterName + ".cs", true, Encoding.UTF8);

            PresenterTemplate pt = new PresenterTemplate();

            string pUsing = string.Empty;
            
            if(Core.config.showUsing)
                pUsing = pt.strUsing(pPresenter[2], pPresenter[3]);

            string pNameSapace = string.Format("Sinacor.UI.{0}.{1}.Presenter", pPresenter[2], pPresenter[3]);
            string pPresenterScope = pt.strPresenter(pNameSapace, pPresenterName, Core.config.showInheriting);

            StringBuilder stbMethod = new StringBuilder();
            StringBuilder stbProperty = new StringBuilder();

            List<Entidade> listTemp = new List<Entidade>();

            foreach (Method mtd in plistaExterna)
            {
                if (pTrv.Nodes[0].Nodes[str].Nodes[mtd.MethodSignature] != null)
                {
                    stbMethod.Append(pt.strMethod(mtd));
                }

                stbProperty.Append(pt.strProperty(new Param(), new Method() { MethodComent = pPresenterName }));

                foreach (Param param in mtd.ParamList)
                {
                    Entidade entIn = null;

                    if (param.ParameterIsParameter)
                    {
                        entIn = new Entidade(param.ParameterType, Enums.Direction.Parameter);
                    }
                    else
                    {
                        entIn = new Entidade(param.ParameterType, Enums.Direction.Entrada);
                    }

                    var Entity = listTemp.Find(delegate(Entidade x)
                    {
                        return (x.NomeEntidade == entIn.NomeEntidade && x.Sentido == entIn.Sentido);
                    });

                    if (Entity == null)
                    {
                        stbProperty.Append(pt.strProperty(param, mtd));
                        listTemp.Add(entIn);
                    }
                }

            }

            pPresenterScope = pt.AppendMethod(pPresenterScope, stbMethod);
            pPresenterScope = pt.AppendProperty(pPresenterScope, stbProperty);

            tw.WriteLine(pUsing);
            tw.WriteLine(pPresenterScope);

            tw.Close();
        }
    }
}
